#include "LeadershipBehaviour.h"
#include <stdio.h>
#include <string.h>

//konstruktor, nastavi premenne v datastorage
LeadershipBehaviour::LeadershipBehaviour()
{
	DATA_STORAGE.leadership.leaderUniform = -1;
	DATA_STORAGE.leadership.attentionToSet = false;
	DATA_STORAGE.leadership.currentFormation = LPT_FR_LJON;
	DATA_STORAGE.leadership.amILeader = false;
	DATA_STORAGE.leadership.lastChangeTime = -1;
	DATA_STORAGE.leadership.lastSendTime = 0;
	DATA_STORAGE.leadership.casZmenyVeduceho = -1;
	DATA_STORAGE.leadership.casZmenyFormacie = -1;
}

/*
 * Urci ci je hrac veducim hry.
 *
 * @return true ak je hrac veducim hry
 */
bool LeadershipBehaviour::GetAmILeader(){
	return DATA_STORAGE.leadership.amILeader;
}

/*
 * Vrati cislo veduceho hry
 *
 * @return cislo veduceho hry
 */
int LeadershipBehaviour::GetLeaderUniform(){
	return DATA_STORAGE.leadership.leaderUniform;
}


/*
 * krici veduci kandidatovi na veduceho
 *
 * @param uniformNumber cislo hraca, ktory je kandidatom
 */
void LeadershipBehaviour::SendTySiLeaderMSG(int uniformNumber)
{
	char msg[8];
	sprintf(msg, "LT___%d", uniformNumber);
	ZakodujSimCas(world->state->GetSimTime(), &msg[2]);

	DATA_STORAGE.leadership.lastSendTime = world->state->GetSimTime();

	fprintf(stderr, "[LPT] u%d t%d: Posielam hracovi %d: Bud veduci!\n", world->me->GetUniform(), world->state->GetSimTime(), uniformNumber);
	commandGenerator->AttentionTo(uniformNumber);
	commandGenerator->Say(msg);
}

/*
 * krici kandidat ako potvrdenie leaderovi staremu
 */
void LeadershipBehaviour::SendOkSomLeaderMSG()
{
	commandGenerator->Say("LK");
}

/*
 * krici stary veduci o novom + hraci medzi sebou
 */
void LeadershipBehaviour::SendLeaderMSG()
{
	char msg[8];

	if (!DATA_STORAGE.leadership.amILeader)
	{
		fprintf(stderr, "[LPT] u%d t%d: Kricim: Hrac %d je veduci.\n", world->me->GetUniform(), world->state->GetSimTime(), DATA_STORAGE.leadership.leaderUniform);
		sprintf(msg, "LJ___%d", DATA_STORAGE.leadership.leaderUniform);
	} 
	else
	{
		//tato vetva sa vyvola len v simulacnom case 0
		fprintf(stderr, "[LPT] u%d t%d: Som veduci, posielam info dalej.\n", world->me->GetUniform(), world->state->GetSimTime());
		sprintf(msg, "LJ___%d", world->me->GetUniform());
	}

	ZakodujSimCas(DATA_STORAGE.leadership.casZmenyVeduceho, &msg[2]);
	commandGenerator->Say(msg);
}

/*
 * krici leader pri zmene formacie
 */
void LeadershipBehaviour::SendZmenaFormacieLeaderMSG()
{
	char msg[8];

	fprintf(stderr, "[LPT] u%d t%d: Kricim: Zoradte sa do formacie %d!\n", world->me->GetUniform(), world->state->GetSimTime(), DATA_STORAGE.leadership.currentFormation);
	sprintf(msg, "LF___%d", (int) DATA_STORAGE.leadership.currentFormation);
	ZakodujSimCas(DATA_STORAGE.leadership.casZmenyFormacie, &msg[2]);
	commandGenerator->Say(msg);
}

/*
 * krici leader pri zmene formacie
 */
void LeadershipBehaviour::SendZmenaFormaciePlayerMSG()
{
	char msg[8];

	fprintf(stderr, "[LPT] u%d t%d: Opakujem prikaz veduceho: Formacia %d\n", world->me->GetUniform(), world->state->GetSimTime(), DATA_STORAGE.leadership.currentFormation);
	sprintf(msg, "Lf___%d", (int) DATA_STORAGE.leadership.currentFormation);
	ZakodujSimCas(DATA_STORAGE.leadership.casZmenyFormacie, &msg[2]);
	commandGenerator->Say(msg);
}

/*
 * Spracovanie spravy od veduceho.
 *
 * @param time cas kedy prisla sprava
 * @param uniform cislo hraca od ktoreho prisla sprava
 * @param msg obsah vlastnej spravy
 */
void LeadershipBehaviour::ProcessLeaderMSG(int time, int uniform, const char *msg)
{
	if (strcmp(msg, "LK") == 0)
	{
		if (DATA_STORAGE.leadership.amILeader)
		{
			if (time - DATA_STORAGE.leadership.lastSendTime <= 3) //tato podmienka by mala byt vzdy splnena, inac nastane problem
			{
				DATA_STORAGE.leadership.amILeader = false;
				DATA_STORAGE.leadership.leaderUniform = uniform;
				DATA_STORAGE.leadership.casZmenyVeduceho = world->state->GetSimTime();
				DATA_STORAGE.leadership.lastChangeTime = world->state->GetSimTime(); //aby sa v tomto a v najblizsom cykle nesnazil nic kricat
				fprintf(stderr, "[LPT] u%d t%d: Vzdal som sa vedenia. Novy veduci je %d.\n", world->me->GetUniform(), world->state->GetSimTime(), uniform);
				SendLeaderMSG();
			}
		}
		return;
	}

	if (strlen(msg) > 5) //dva znaky su druh spravy, tri znaky cas
	{
		int msgTime = OdkodujSimCas(&msg[2]);

		if (strncmp(msg, "LT", 2) == 0)
		{
			//veduci poslal prikaz, ze mam byt novy veduci; treba mu poslat LOK
			if (world->state->GetSimTime() - msgTime <= 1 &&
				atoi(msg+5) == world->me->GetUniform())
			{
				DATA_STORAGE.leadership.amILeader = true;
				DATA_STORAGE.leadership.leaderUniform = world->me->GetUniform();
				DATA_STORAGE.leadership.casZmenyVeduceho = world->state->GetSimTime();
				DATA_STORAGE.leadership.lastChangeTime = world->state->GetSimTime(); //aby sa v tomto a v najblizsom cykle nesnazil nic kricat
				fprintf(stderr, "[LPT] u%d t%d: Prijal som poziadavku, ze mam byt veduci a suhlasim.\n", world->me->GetUniform(), world->state->GetSimTime());
				SendOkSomLeaderMSG();
				commandGenerator->AttentionOff();
				return;
			}
		} else
			if (strncmp(msg, "LJ", 2) == 0)
			{
				//hrac/veduci poslal oznam, kto je veduci
				if (!DATA_STORAGE.leadership.amILeader && DATA_STORAGE.leadership.leaderUniform != atoi(msg+5) && msgTime > DATA_STORAGE.leadership.casZmenyVeduceho)
				{
					DATA_STORAGE.leadership.leaderUniform = atoi(msg+5);
					DATA_STORAGE.leadership.casZmenyVeduceho = msgTime;
					commandGenerator->AttentionTo(DATA_STORAGE.leadership.leaderUniform); //pocuvam veduceho
					SendLeaderMSG(); //oznamim svetu, kto je veduci
					return;
				}
			}	else
				if (strncmp(msg, "LF", 2) == 0)
				{
					//veduci poslal prikaz na zmenu formacie
					if (!DATA_STORAGE.leadership.amILeader && msgTime > DATA_STORAGE.leadership.casZmenyFormacie)
					{
						int forID;
						forID = atoi(msg+5);
						DATA_STORAGE.leadership.currentFormation = (LPT_FormationType) forID;
						DATA_STORAGE.leadership.casZmenyFormacie = msgTime;
						if (uniform != DATA_STORAGE.leadership.leaderUniform)
						{ //mam zlu informaciu o veducom -> upravujem
							DATA_STORAGE.leadership.leaderUniform = uniform;
							DATA_STORAGE.leadership.casZmenyVeduceho = msgTime;
							commandGenerator->AttentionTo(DATA_STORAGE.leadership.leaderUniform);
						}
						SendZmenaFormaciePlayerMSG();
					}
				} else
					if (strncmp(msg, "Lf", 2) == 0 && msgTime > DATA_STORAGE.leadership.casZmenyFormacie)
					{
						if (!DATA_STORAGE.leadership.amILeader)
						{
							//hrac zopakoval prikaz na zmenu formacie od veduceho
							int forID;
							forID = atoi(msg+5);
							DATA_STORAGE.leadership.casZmenyFormacie = msgTime;
							if (DATA_STORAGE.leadership.currentFormation != (LPT_FormationType) forID)
							{
								DATA_STORAGE.leadership.currentFormation = (LPT_FormationType) forID;
								fprintf(stderr, "[LPT] u%d t%d: Od hraca %d som zistil, ze sucasna formacia je %d\n", world->me->GetUniform(), world->state->GetSimTime(), uniform, DATA_STORAGE.leadership.currentFormation);
							}
						}
					} else
					{
						//ziadna zaujimava sprava -> /dev/null :P
						return;
					}
	} else
	{
		// ziadna zaujimava sprava -> /dev/null :P
		return;
	}
}